package com.seeyon.ctp.common.web.filter;


import com.seeyon.ctp.cluster.ClusterConfigBean;
import com.seeyon.ctp.common.AppContext;
import com.seeyon.ctp.common.GlobalNames;
import com.seeyon.ctp.common.authenticate.LockLoginInfoFactory;
import com.seeyon.ctp.common.authenticate.domain.User;
import com.seeyon.ctp.common.config.IConfigPublicKey;
import com.seeyon.ctp.common.config.SystemConfig;
import com.seeyon.ctp.common.constants.Constants;
import com.seeyon.ctp.common.constants.LoginResult;
import com.seeyon.ctp.common.flag.SysFlag;
import com.seeyon.ctp.common.i18n.ResourceUtil;
import com.seeyon.ctp.common.po.restlog.CtpRestLogs;
import com.seeyon.ctp.common.restlog.manager.CtpRestLogsManager;
import com.seeyon.ctp.common.web.util.WebUtil;
import com.seeyon.ctp.login.CurrentUserToSeeyonApp;
import com.seeyon.ctp.login.LoginTokenUtil;
import com.seeyon.ctp.rest.util.RestUrlFilterUtil;
import com.seeyon.ctp.rest.util.TokenUtil;
import com.seeyon.ctp.rest.vo.RestResourceGroupVO;
import com.seeyon.ctp.services.security.ServiceManager;
import com.seeyon.ctp.usersystem.manager.ResourceGroupManager;
import com.seeyon.ctp.usersystem.manager.RestUserManager;
import com.seeyon.ctp.usersystem.po.RestUser;
import com.seeyon.ctp.util.Cookies;
import com.seeyon.ctp.util.Strings;
import com.seeyon.oainterface.common.OAInterfaceException;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Pattern;

/**
 * REST身份校验。
 *
 * @author wangwenyou
 */
public class RestAuthenticator extends AbstractAuthenticator {
    private static final Logger log = Logger
            .getLogger(RestAuthenticator.class);
    protected RestUserManager restUserManager;

    protected ResourceGroupManager resourceGroupManager;

    private SystemConfig systemConfig = null;
    // Session用户访问黑名单
    protected static Collection<Pattern> sessionUserBlacklist = new CopyOnWriteArrayList<Pattern>();

    static {
        sessionUserBlacklist.add(Pattern.compile(".*\\sorgMember.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sorgAccount.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sorgDepartment.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sorgPost.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sorgLevel.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sexternalAccount.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sorgPartTimeJob.*"));

        sessionUserBlacklist.add(Pattern.compile(".*\\sjoinOrgAccount.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sjoinOrgDepartment.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sjoinOrgPost.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sjoinOrgMember.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sjoinOrgRole.*"));
        sessionUserBlacklist.add(Pattern.compile(".*\\sjoinMetadataDepartment.*"));
    }



    // 无需Token可访问的白名单
    private static List<String> anonymousWhiteList = Arrays.asList("token", "application.wadl",
            "jssdk", "getRestCompare","authentication",
            "cap4/form/pluginScripts",
            "orgMember/avatar", "orgMember/groupavatar",
            "m3/appManager/getAppList",//获取需要更新的应用包
            "m3/appManager/download", //M3应用包下载
            "m3/message/unreadCount/", //获取待办消息数，用于关联账号的未读消息数显示
            "m3/login/refresh",//通过token刷新身份
            "m3/login/verification",//登录接口
            "m3/theme/homeSkin",//启动页
            "m3/theme/homeSkinDownload",//启动页下载
            "m3/common/service/enabled",// M3 服务启动时检查OA服务是否能正常访问的接口，此接口无参数，固定返回true。无需登录。
            "uc/systemConfig",
            "product/hasPlugin",
            "product/dongle/data",
            "password/retrieve",
            "phoneLogin/phoneCode",
//            "m3/trustdo/sdk/login/event",
//            "m3/trustdo/sdk/keyId",
//            "m3/trustdo/sdk/cert/event",
//            "m3/trustdo/sdk/login/name",
//            "m3/trustdo/sdk/server/info",
            "m3/appManager/checkEnv",        // M3 检测版本号和更新地址
            "m3/security/device/apply",     //M3 硬件绑定的申请接口
            "meeting/meetingInviteCard",
            "microservice",
            "media/verify",
            "paperlessMeetingResource/device/save",//绑定设备信息
            "metrics",       //量测采集接口，只查询状态
            "ocip/forwardTo",
            "imc/orgInfo");//华为imc组织机构同步，本身接口带有鉴权功能
    // Guest可访问的白名单
    private static List<String> guestWhiteList = Arrays.asList("webOffice/checkWebOfficeEnable","webOffice/getBookMarkUpdateFlag","supervision/bigScreen/column");
    // Visitor可访问的白名单
    private static List<String> visitorWhiteList = Arrays.asList("publicQrCode", "attachment", "commonImage", "m3/common/getConfigInfo", "meeting", "cmpNews", "doc");
    // REST 访问日志记录
    protected CtpRestLogsManager ctpRestLogsManager;
    public void setCtpRestLogsManager(CtpRestLogsManager ctpRestLogsManager) {
        this.ctpRestLogsManager = ctpRestLogsManager;
    }

    public CtpRestLogsManager getCtpRestLogsManager() {
        if (ctpRestLogsManager == null) {
            ctpRestLogsManager = (CtpRestLogsManager) AppContext.getBean("ctpRestLogsManager");
        }
        return ctpRestLogsManager;
    }

    public void setRestUserManager(RestUserManager restUserManager) {
        this.restUserManager = restUserManager;
    }

    public RestUserManager getRestUserManager() {
        if (restUserManager == null) {
            restUserManager = (RestUserManager) AppContext.getBean("restUserManager");
        }
        return restUserManager;
    }

    public void setResourceGroupManager(ResourceGroupManager resourceGroupManager) {
        this.resourceGroupManager = resourceGroupManager;
    }

    public ResourceGroupManager getResourceGroupManager() {
        if (resourceGroupManager == null) {
            resourceGroupManager = (ResourceGroupManager) AppContext.getBean("resourceGroupManager");
        }
        return resourceGroupManager;
    }


    protected boolean isIgnoreToken(String path) {
        for (String string : anonymousWhiteList) {
            if (string.equals(path)) {
                return true;
            }
            if (path.startsWith(string)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean authenticate(HttpServletRequest request, HttpServletResponse response) {
        // 去掉  /contextPath/rest/xx   => xx
        String path = request.getRequestURI().substring(request.getContextPath().length() + "/rest/".length());
        initContext(request, response);
        String ip = Strings.getRemoteAddr(request);// req.getUriInfo().getBaseUri().getHost();
        // 写REST 访问日志
        CtpRestLogs ctpLog = new CtpRestLogs();
        ctpLog.setExeurl(path);
        ctpLog.setLoginIp(ip);

        // 是否为匿名范围资源
        boolean isAnonymousUrl = isIgnoreToken(path);
        if (!isAnonymousUrl) {
            String token = getToken(request);
            if (!Strings.isEmpty(token) && !"null".equalsIgnoreCase(token)
                    && ServiceManager.getInstance().checkTokenValidity(token)
            ) {
//                try {
//                    //不用checkToken，用activeToken，activeToken有判断token是否过期
//                    ServiceManager.getInstance().activeToken(token);
//                } catch (OAInterfaceException e) {
//                    unauthorized(request, e.getUserMsg());
//                    return true;
//                }

                // 写REST 访问日志
                ctpLog.setToken(token);

                // 验证用户是否有访问此URI权限 start
                String loginName = ServiceManager.getInstance().getUserNameByToken(token);
                try {
                    RestUser user = getRestUserManager().getUserByLoginName(loginName);
                    if (user == null) {
                        // customRestUser暂时放过去，不做处理。后续对customRestUser策略做优化
                        if (!ServiceManager.CUSTOM_REST_USER_NAME.equals(loginName)){
                            boolean isClusterRequest = false;
                            if (ClusterConfigBean.getInstance().isClusterEnabled()) {
                                String remoteAddr = Strings.getRemoteAddr(request);
                                if (ClusterConfigBean.getInstance().getHosts().indexOf(remoteAddr) > 0) {
                                    isClusterRequest = true;
                                }
                            }
                            if (!isClusterRequest) {
                                ctpLog.setStatus("0获取REST用户失败！");
                                getCtpRestLogsManager().insertLog(ctpLog);
                                unauthorized(request, "获取REST用户失败！");
                                log.info("获取REST用户失败：" + path + ", " + ip);
                                return true;
                            }
                        }
                    }
                    else {

                        // 检查强制绑定的ip是否满足，对vjoin不做接口调用上的token绑定校验
                        if (!("vjoin".equals(user.getUserName()) && "v_join".equals(user.getType())) &&
                                !TokenUtil.checkAccessTokenIpForRestUser(user, request)) {
                            unauthorized(request, "访问IP不在允许内！");
                            log.info("访问IP不在允许内：" + path + ", " + TokenUtil.getRemoteAddr(request));
                            return true;
                        }

                        AppContext.putThreadContext(GlobalNames.THREAD_CONTEXT_REST_USER,user);
                        // 写REST 访问日志
                        ctpLog.setUserId(user.getId());
                        ctpLog.setLoginType("T");//rest方式登录
                    }

                    // start helgen
                    //先判断当前用户所访问的 rest url 是否在服务组集合中[DEE服务;文档导出服务;
                    // 工作计划服务;定位服务;表单流程服务;组织模型服务;公共信息服务;
                    // 会议服务;日程事件服务;事项集成服务;系统消息服务;群杰智能印章服务;]
                    // 获取 12 大类及对应的资源相关信息
                    List<RestResourceGroupVO> resourceGroupVOS =  getResourceGroupManager().getRestResourceGroupVO(user != null && user.isSystemChannel());
                    // 获取 12 大类的所对应的的路径
                    Map<String,String> ruiTypeMap = this.getResourceUri(resourceGroupVOS);
                    // 当前访问的路径验证
                    String uriKey = this.uriVerification(path,ruiTypeMap);
                    if(StringUtils.isNotBlank(uriKey)){// 判断当前请求的资源路径是否需要验证
                        String groupType = ruiTypeMap.get(uriKey);
                        boolean falg = this.authorityVerification(user,groupType);

                        // 判断当前的用户的用户名是否是微协同的特定的用户
                        if(isSpecialUser(user)){
                            falg = true;// 把当前登录名改为微协同的用户名;
                        }

//                        if(!falg){
//                            // 当前 rest 用户无权限访问请求的资源的路径
//                            String message =" "+loginName + "无权限访问" + path + "需授权";
//                            unauthorized(request, "2248" + message);
//                            log.info(message + "_1：" + path + ", " + ip);
//                            return true;
//                        }
                    }
//                    else if((Boolean)SysFlag.sys_isA6Ver.getFlag() && isRestUser(user) && !isSpecialUser(user)){
//                        //A6版本下除开指定特殊用户，目前只放开群杰印章接口权限,
//                        // 当前 rest 用户无权限访问请求的资源的路径
//                        String message =" "+loginName + "无权限访问" + path + "需授权";
//                        unauthorized(request, "2248" + message);
//                        log.info(message + "_2：" + path + ", " + ip + ", A6 不支持普通rest接口调用");
//                        return true;
//                    }

                    // 校验通过后，才进行init user，由于安全问题，从最前面移植到所有校验后来做
                    AppContext.putThreadContext(GlobalNames.THREAD_CONTEXT_SESSION_KEY, request.getSession(true));
                    AppContext.putSessionContext(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, request.getLocale());
                    ServiceManager.getInstance().initCurrentUser(request, token);
                    User currentUser = AppContext.getCurrentUser();
                    if (currentUser != null) {
                        if (currentUser.isGuest()) {
                            if (!isGuestAccessable(path)) {
                                unauthorized(request, "该资源不允许Guest访问：" + path);
                                log.info("该资源不允许Guest访问：" + path + ", " + ip);
                                return true;
                            }
                        } else if (currentUser.isVisitor()) {
                            if (!isVisitorAccessable(path)) {
                                unauthorized(request, "该资源不允许Visitor访问：" + path);
                                log.info("该资源不允许Visitor访问：" + path + ", " + ip);
                                return true;
                            }
                        }

                        String accountLockMode = getSystemConfig().get(IConfigPublicKey.ACCOUNT_LOCK_MODE);
                        if ("account".equals(accountLockMode)){
                            int USER_LOGIN_COUNT = Integer.parseInt(getSystemConfig().get(IConfigPublicKey.ACCOUNT_LOCK_TIMES));
                            long FORBIDDEN_LOGIN_TIME = Integer.parseInt(getSystemConfig().get(IConfigPublicKey.ACCOUNT_LOCK_TIME)) * 3600000L;//配置单位为小时，转为毫秒
                            for (Constants.login_sign sign : Constants.login_sign.values()){
                                LockLoginInfoFactory.LockLoginInfo info = LockLoginInfoFactory.getInstance().get(currentUser.getLoginName(), sign.value());
                                if (("enable".equals(getSystemConfig().get(IConfigPublicKey.IS_OPEN_LOCK_PROTECT))) && info != null && info.getCount() >= USER_LOGIN_COUNT) {// 禁止登录时间单位为分钟
                                    String msg = "2248" + ResourceUtil.getString("loginUserState.accountLock");
                                    unauthorized(request, msg);
                                    log.info(msg + "_3：" + path + ", " + ip);
                                    return true;
                                }
                            }
                        }
                    }

                } catch (Throwable e1) {
                    ctpLog.setStatus("0获取REST用户失败！");
                    log.error("获取REST用户失败！" + e1.getLocalizedMessage() + ", " + path + ", " + ip, e1);
                }
                // 验证用户是否有访问此URI权限 end

//                try {
                ctpLog.setStatus(ctpLog.getStatus() == null ? "1" : ctpLog.getStatus());
//                } catch (Exception e) {
//                    ctpLog.setStatus("0");
//                    unauthorized(request, e.getLocalizedMessage());
//                    return true;
//                }
            }
            else {
                HttpSession session = request.getSession(false);
                boolean hasCurrentUser = session != null && session.getAttribute(Constants.SESSION_CURRENT_USER) != null;
                if (hasCurrentUser) {
                    User currentUser = AppContext.getCurrentUser();
                    if (currentUser == null) {
                        unauthorized(request, "Session没有对应的登录用户");
                        log.info("Session没有对应的登录用户：" + path + ", " + ip);
                        return true;
                    }
                    if (currentUser.isGuest()) {
                        if (!isGuestAccessable(path)) {
                            unauthorized(request, "该资源不允许Guest访问：" + path);
                            log.info("该资源不允许Guest访问：" + path + ", " + ip);
                            return true;
                        }
                    } else if (currentUser.isVisitor()) {
                        if (!isVisitorAccessable(path)) {
                            unauthorized(request, "该资源不允许Visitor访问：" + path);
                            log.info("该资源不允许Visitor访问：" + path  + ", " + ip);
                            return true;
                        }
                    }

                    // 在线状态
                    String message1 = CurrentUserToSeeyonApp.getUserOnlineMessage(request,true);
                    if (message1 != null) {
                        unauthorized(request, message1);
                        log.info("在线状态异常：" + message1 + ", " + path + ", " + ip);
                        return true;
                    }

                    // 不允许session用户访问的url
                    String input = request.getMethod() + " " + path;
                    for (Pattern p : sessionUserBlacklist) {
                        if (p.matcher(input).find()) {
                            unauthorized(request, "请使用Token，Session登录不允许访问该接口：" + path);
                            log.info("请使用Token，Session登录不允许访问该接口：" + path + ", " + ip);
                            return true;
                        }
                    }

                    // 初始化系统环境上下文
                    AppContext.initSystemEnvironmentContext(request, response);

                    // 写REST 访问日志
                    String[] sessionMap;
                    try {
                        sessionMap = session.getAttribute(Constants.SESSION_CURRENT_USER).toString().split("	");
                        ctpLog.setUserId(Long.parseLong(sessionMap[0]));
                    } catch (Exception e) {
                        unauthorized(request, "会话已失效。");
                        log.info("会话已失效：" + path + ", " + ip);
                        return true;
                    }

                    ctpLog.setToken(session.getId());
                    ctpLog.setLoginType("S");
                    ctpLog.setStatus("1");

                }
                else {
                    //=========m3添加的logintoken校验机制====start=========
                    LoginResult loginResult = LoginTokenUtil.checkLoginToken(request);
                    if (loginResult.isOK()) {
                        ctpLog.setToken(request.getHeader("ltoken"));
                        ctpLog.setLoginType("L");//ltoken 方式激活
                        ctpLog.setStatus("1");
                    } else {
                        ctpLog.setToken("invalid");
                        ctpLog.setUserId(0);
                        ctpLog.setLoginType("S");//ltoken 方式激活失败
                        ctpLog.setStatus("0");
                        String error = loginResult.getStatus() == 1010 ? ResourceUtil.getString("loginUserState.unknown")
                                : ResourceUtil.getString("login.label.ErrorCode." + loginResult.getStatus());
                        unauthorized(request, loginResult.getStatus() + ":" + error);
                        log.info(error + ":" + loginResult.getStatus() + ", " + path + ", " + ip);
                        return true;
                    }
                    //=========m3添加的logintoken校验机制====end=========
                }
            }

            getCtpRestLogsManager().insertLog(ctpLog);
        }
        // 补偿，调整为false后，有的应用调用AppContext.getSessionContext报错
        HttpSession session = request.getSession(false);
        if (session == null) {
            session = request.getSession(true);
            AppContext.putThreadContext(GlobalNames.THREAD_CONTEXT_SESSION_KEY, session);
            AppContext.putSessionContext(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, request.getLocale());
        }
        if(!"track/log".equals(path)){
            updateAccessTimestamp();
        }
        return true;
    }

    private boolean isSpecialUser(RestUser user) {
        if(user!=null){
            if (("wechat").equals(user.getUserName())
                    || ("vjoin").equals(user.getUserName())
                    || ("seeyons1").equals(user.getUserName())
                    || ("seeyonBI").equals(user.getUserName())
                    || ("seeyonbiinside").equals(user.getUserName())) {
                return true;// 把当前登录名改为微协同的用户名;
            }
        }
        return false;
    }

    private boolean isRestUser(RestUser user) {
        if (user != null && user.isSystemChannel()) {
            return false;
        }
        return true;
    }

    @Override
    public boolean validate(String uri, HttpServletRequest req) {
        return uri.startsWith(req.getContextPath()+"/rest/");
    }

    private void initContext(HttpServletRequest request, HttpServletResponse response) {

        AppContext.clearThreadContext();
//		User user = null;
//        try {
//            user = (User) AppContext.getSessionContext(Constants.SESSION_CURRENT_USER);
//        } catch (InfrastructureException e) {
//            // 保证用户不登录也能不抛异常，返回null。4定时任务。
//        }
        // Rest请求无状态，直接清除ThreadLocal中的用户缓存，以免发生混混乱
        AppContext.removeThreadContext(GlobalNames.SESSION_CONTEXT_USERINFO_KEY);

        HttpSession session = request.getSession(false);
        if (session != null) {
            AppContext.putThreadContext(GlobalNames.THREAD_CONTEXT_SESSION_KEY, session);
            if(AppContext.getSessionContext(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME) == null){
                AppContext.putSessionContext(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME, request.getLocale());
            }
        }
        AppContext.putThreadContext(GlobalNames.THREAD_CONTEXT_REQUEST_KEY, request);
        WebUtil.setRequest(request);
        WebUtil.setResponse(response);
    }

    /**
     * 获取请求中的token
     *
     * @param request REST请求
     * @return token
     */
    public static String getToken(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (Strings.isEmpty(token)) {
            token = request.getParameter("token");
        }
        if (Strings.isEmpty(token)) {
            token = Cookies.get(request, "token");
        }
        return token;
    }

    private boolean isGuestAccessable(String path) {
        for (String string : guestWhiteList) {
            if (path.startsWith(string)) {
                return true;
            }
        }
        return false;
    }

    private boolean isVisitorAccessable(String path) {
        for (String string : visitorWhiteList) {
            if (path.startsWith(string)) {
                return true;
            }
        }
        return false;
    }

    void unauthorized(Object req, String message) {
        AppContext.putThreadContext("REST_UNAUTHORIZED_MESSAGE", message);
    }



    // start helg 20191221

    /**
     * 验证当前用户是否有权限访问此资源路径
     * by helgen
     *
     * @param user 当前 rest 用户
     * @param groupType 当前 rest 用户请求资源对应的大类的类型
     * @return false: 无权限；true：有权限
     */
    private boolean authorityVerification(RestUser user, String groupType) {
        boolean flag = false;// 判断标识
        if (StringUtils.isNotBlank(groupType) && user != null && user.getResourceAuthority() != null) {// 非空判断
            String[] resources = user.getResourceAuthority().split("");//拆分为数组
            int groupTypeNum = Integer.valueOf(groupType);// 获得当前的组权限类型
            if (groupTypeNum <= resources.length) {// 判断当前组的类型是否超出了当前用户允许的范围
                //根据资源组的在资源组合中的位数获取是否选中，用于显示checkb的选中与否
                if ("1".equals(resources[groupTypeNum - 1])) {// 判断当前组的类型是否授权给了当前的用户
                    flag = true;
                }
            }
        }
        return flag;
    }

    /**
     * 当前访问的路径验证
     * by helgen
     * @param path 访问的路径
     * @param ruiTypeMap 资源路径及大类类型数据集合
     * @return
     */
    private String uriVerification(String path, Map<String,String> ruiTypeMap){
        String uriKey = "";// 存储器：记录需要拦截的路径的值
        if(ruiTypeMap != null && ruiTypeMap.size() > 0){// 非空判断
            for(Map.Entry<String,String> ruiType : ruiTypeMap.entrySet()){
                String pattern =  ruiType.getKey();
                boolean flag = RestUrlFilterUtil.checkUrl(path, pattern);// 正则表达式 验证当前用户是否有当前访问 rest 的权限;
                if (flag) {
                    uriKey = pattern;
                    break;
                }
            }
        }
        return uriKey;
    }

    /**
     * 获取 11 大类的所对应的的路径
     * by helgen
     * @param resourceGroupVOS rest 授权vo
     * @return
     */
    private Map<String,String> getResourceUri(List<RestResourceGroupVO> resourceGroupVOS) {
        Map<String,String> ruiTypeMap = new HashMap<>();// 存储器：key:请求资源的路径; value: 11大类的类别
        if (resourceGroupVOS != null && resourceGroupVOS.size() > 0) {// 非空判断

            for (RestResourceGroupVO vo : resourceGroupVOS) {// 获取权限组对应的 rest url 集合
                String resourceUrl = vo.getResourceUri();// 获取请求的资源的地址路径
                String[] uris = resourceUrl.split("/");

                StringBuffer uriBuffer = new StringBuffer();
                for (int i = 0; i < uris.length; i++) {// 重新组装数据，如果{}数据替换为 正则表达式
                    String uri = uris[i];
                    if (uri != null && uri.trim().length() > 0) {
                        if (uri.indexOf("{") != -1) {
                            String str = uri.replaceAll("\\{[^}]*\\}", "(.*?)");
                            uriBuffer.append(str).append("/");
                        } else {
                            uriBuffer.append(uri + "/");
                        }
                    }
                }
                String uri = uriBuffer.substring(0, uriBuffer.length() - 1);
                ruiTypeMap.put(uri,vo.getGroupType());
            }
        }
        return ruiTypeMap;
    }

    public SystemConfig getSystemConfig() {
        if(systemConfig == null){
            systemConfig = (SystemConfig)AppContext.getBean("systemConfig");
        }
        return systemConfig;
    }

    // end helg 20191221
}
